package com.cell.api.application.netty.server;

import com.cell.api.application.netty.code.Packet;
import com.cell.api.application.netty.handler.base.HandlerFactory;
import com.cell.api.application.netty.handler.base.IBaseHandler;
import com.cell.api.application.netty.utils.ChannelHashMap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * <p>
 * netty服务端处理器
 * </p>
 *
 * @author zdy
 * @date 2021/11/6
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {


    /**
     * 客户端注册触发
     *
     * @param ctx 上下文通道对象
     * @throws Exception 异常
     */
    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端注册");
    }

    /**
     * 客户端退出注册触发
     *
     * @param ctx 上下文通道对象
     * @throws Exception 异常
     */
    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
    }

    /**
     * 客户端连接成功触发
     *
     * @param ctx 上下文通道对象
     * @throws Exception 异常
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ChannelHashMap.putChannel("test", ctx.channel());
        log.info("客户端连接成功");
    }


    /**
     * 客户端失去连接触发-移除登陆信息
     *
     * @param ctx 上下文通道对象
     * @throws Exception 异常
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端失去连接");
        ChannelHashMap.removeChannelByName("test");
    }

    /**
     * 读取客户端发送消息会触发-处理消息
     *
     * @param ctx 上下文通道对象
     * @param msg 消息内容
     * @throws Exception 异常
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("服务器收到消息: {}", msg);
        Packet packet = (Packet) msg;
        //根据功能码，获取不同handler实例（可以用策略模式、工厂模式），这里用工厂模式
        IBaseHandler handler = HandlerFactory.createHandler(packet.getGetCommand());
        if (handler == null) {
            log.error("找不到对应的handler,指令：{}", packet.getGetCommand());
            return;
        }
        //开始处理解析tcp协议请求报文内容，这里例子是水电表的集中器（dtu）数据内容
        handler.doRequest(packet.getDataLength(), packet.getBytes());
        //响应回去给发送者信息
        byte[] res = handler.doResponse();
        ctx.flush();
        log.info("服务器返回客户端响应消息: {}", res);
        if (res != null) {
            ctx.write(res);
        }
    }


    /**
     * 读取客户端发送消息完成会触发
     *
     * @param ctx 上下文通道对象
     * @throws Exception 异常
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端发送消息完成");
    }

    /**
     * 事件处理
     *
     * @param ctx 上下文通道对象
     * @param evt 事件对象
     * @throws Exception 异常
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            switch (e.state()) {
                case WRITER_IDLE:
                    log.info("WRITER_IDLE");
                    break;
                case READER_IDLE:
                    log.info("READER_IDLE");
                    break;
                case ALL_IDLE:
                    //送心跳
                    log.info("ALL_IDLE");
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 发生异常
     *
     * @param ctx   上下文通道对象
     * @param cause 异常类
     * @throws Exception 异常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("发生异常:", cause);
        cause.printStackTrace();
        ctx.close();
    }
}
